#include <osa.h>
#include <avr/io.h>
#include <stdio.h> 

#include "keyin.h"
#include "disp.h"
#include "rtc.h"

#define KEY_MODE_PORT 	PORTD
#define KEY_MODE_PIN  	PIND
#define KEY_MODE_DIR  	DDRD
#define KEY_MODE  		PD2

#define KEY_UP_PORT 	PORTD
#define KEY_UP_PIN  	PIND
#define KEY_UP_DIR  	DDRD
#define KEY_UP  		PD3

#define KEY_DOWN_PORT 	PORTD
#define KEY_DOWN_PIN  	PIND
#define KEY_DOWN_DIR  	DDRD
#define KEY_DOWN		PD5


#define KEY_TIME_INIT	50 ms
#define KEY_UP_COUNT	3
#define KEY_HOLD_COUNT	(KEY_UP_COUNT * 6)
#define KEY_DOWN_COUNT	KEY_UP_COUNT * 2

OST_SMSG  os_smsg_keyin;

struct SKeyInData
{
    unsigned char state;
    unsigned char up_count;
    unsigned char down_count;
}
KeyMode,KeyUp,KeyDown;

void doInitKey(struct SKeyInData * key,char key_id);
void doDecKeyCount(struct SKeyInData * key);
void doIncKeyCount(struct SKeyInData * key);
void doKeyDetect(void);
/********************************************************************************
 *                                                                              *
 *  TASK:           InitKeyIN                                                   * 
 *                                                                              *
 *------------------------------------------------------------------------------*
 *
 *  description:    
 *
 ********************************************************************************/
void InitKeyIN( void )
{
	KEY_MODE_DIR &= ~_BV(KEY_MODE);
	KEY_UP_DIR 	 &= ~_BV(KEY_UP);
	KEY_DOWN_DIR &= ~_BV(KEY_DOWN);

	doInitKey(&KeyMode,KEY_MODE_ID);
	doInitKey(&KeyUp,KEY_UP_ID);
	doInitKey(&KeyDown,KEY_DOWN_ID);
	
	OS_Smsg_Create(os_smsg_keyin);
}

/********************************************************************************
 *                                                                              *
 *  TASK:           doIncKeyCount                                                   * 
 *                                                                              *
 *------------------------------------------------------------------------------*
 *
 *  description:    
 *
 ********************************************************************************/
void doInitKey(struct SKeyInData * key,char key_id)
{
	key->state = key_id & 0xF0;
	key->up_count = 0x00;
	key->down_count = 0x00;
	
}

/********************************************************************************
 *                                                                              *
 *  TASK:           doIncKeyCount                                                   * 
 *                                                                              *
 *------------------------------------------------------------------------------*
 *
 *  description:    
 *
 ********************************************************************************/
void doIncKeyCount(struct SKeyInData * key)
{
	char key_id = key->state & 0xF0;
	if( key->up_count < KEY_HOLD_COUNT )	
	{
		key->up_count += 1;
		if( key->up_count == KEY_UP_COUNT )
		{
			key->state = key_id | KEY_UP_CODE;
			key->down_count = 0;
		}
		else if( key->up_count == KEY_HOLD_COUNT )	
		{
			key->state  = key_id | KEY_HOLD_CODE;			
			key->down_count = 0;
		}
	}	
}

/********************************************************************************
 *                                                                              *
 *  TASK:           doDecKeyCount                                                   * 
 *                                                                              *
 *------------------------------------------------------------------------------*
 *
 *  description:    
 *
 ********************************************************************************/
void doDecKeyCount(struct SKeyInData * key)
{
	char key_id = key->state & 0xF0;
	
	if( key->down_count < KEY_DOWN_COUNT )	
	{
		key->down_count += 1;
		if( key->down_count == KEY_DOWN_COUNT )
		{			
			if( key->up_count >= KEY_UP_COUNT )
			{
				key->state = key_id | KEY_DOWN_CODE;
				key->up_count = 0;			
			}
			else
				key->state = key_id | KEY_NULL_CODE;
		}
	}	
}


/********************************************************************************
 *                                                                              *
 *  TASK:           TaskKeyIN                                                   * 
 *                                                                              *
 *------------------------------------------------------------------------------*
 *
 *  description:    
 *
 ********************************************************************************/
void doKeyDetect(void)
{
	if( bit_is_clear(KEY_MODE_PIN,KEY_MODE) )
		doIncKeyCount(&KeyMode);
	else
		doDecKeyCount(&KeyMode);	
		
	if( bit_is_clear(KEY_UP_PIN,KEY_UP) )
		doIncKeyCount(&KeyUp);
	else
		doDecKeyCount(&KeyUp);	

	if( bit_is_clear(KEY_DOWN_PIN,KEY_DOWN) )
		doIncKeyCount(&KeyDown);
	else
		doDecKeyCount(&KeyDown);		
}

/********************************************************************************
 *                                                                              *
 *  TASK:           doKeyEncode                                                   * 
 *                                                                              *
 *------------------------------------------------------------------------------*
 *
 *  description:    
 *
 ********************************************************************************/
void doKeyEncode(struct SKeyInData * key)
{
	char key_id = key->state & 0xF0;
	
	if( (key->state & 0x0F) != KEY_NULL_CODE )
	{
		//@TH printf("KEY 0x%02X\r\n",key->state);
		
		//OS_Smsg_Send(os_smsg_keyin, (OST_SMSG)key->state);
		OS_Smsg_Send_Now(os_smsg_keyin, (OST_SMSG)key->state);
		
		key->state = key_id | KEY_NULL_CODE;
	}	
}
/********************************************************************************
 *                                                                              *
 *  TASK:           TaskKeyIN                                                   * 
 *                                                                              *
 *------------------------------------------------------------------------------*
 *
 *  description:    
 *
 ********************************************************************************/
void TaskKeyIN (void)
{
	char key_switch = 0;
	
	// printf("TaskKeyIN\r\n");
	
    for (;;)
    {	
		OS_Delay( KEY_TIME_INIT );		
		//OS_Yield();	
		doKeyDetect();
		
		switch(key_switch)
		{
			case 0:
				doKeyEncode(&KeyMode);
				key_switch++;
				break;

			case 1:
				doKeyEncode(&KeyUp);
				key_switch++;
				break;

			case 2:
			default:
				doKeyEncode(&KeyDown);
				key_switch = 0;
				break;
		}

    }
}


